#include "Shader.h"
#include "Log.h"

namespace SCION_RENDERING
{
  GLuint Shader::GetUniformLocation(const std::string &uniformName)
  {
    auto uniformItr = m_UniformLoacationMap.find(uniformName);
    if (uniformItr != m_UniformLoacationMap.end())
    {
      return uniformItr->second;
    }

    GLuint location = glGetUniformLocation(m_ShaderProgramID, uniformName.c_str());
    if (location == GL_INVALID_INDEX)
    {
      SCION_ERROR("Uniform [" + uniformName + "] not found in the shader!");
      return -1;
    }
    m_UniformLoacationMap.emplace(uniformName, location);

    return location;
  }
  Shader::Shader() 
      :Shader(0,"","")
  {

  }
  Shader::Shader(GLuint program, const std::string vertexPath, const std::string &fragmentPath)
      : m_ShaderProgramID(program), m_sVertexPath(vertexPath), m_sFragmentPath(fragmentPath)
  {
  }

  Shader::~Shader()
  {
    if (m_ShaderProgramID > 0)
    {
      glDeleteProgram(m_ShaderProgramID);
    }
  }

  void Shader::SetUniformInt(const std::string &name, int value)
  {
    glUniform1i(GetUniformLocation(name), value);
  }

  void Shader::SetUniformMat4(const std::string &name, const glm::mat4 &mat)
  {
    glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, &mat[0][0]);
  }

  void Shader::Enable()
  {
    glUseProgram(m_ShaderProgramID);
  }

  void Shader::Disable()
  {
    glUseProgram(0);
  }

  void Shader::SetUniformFloat(const std::string &name, float value)
  {
    glUniform1f(GetUniformLocation(name), value);
  }

  void Shader::SetUniformVec2(const std::string &name, const glm::vec2 &value)
  {
    glUniform2f(GetUniformLocation(name), value.x, value.y);
  }

  void Shader::SetUniformVec3(const std::string &name, const glm::vec3 &value)
  {
    glUniform3f(GetUniformLocation(name), value.x, value.y, value.z);
  }

  void Shader::SetUniformVec4(const std::string &name, const glm::vec4 &value)
  {
    glUniform4f(GetUniformLocation(name), value.x, value.y, value.z, value.w);
  }
}
